package com.atguigu.tingshu.album.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.atguigu.tingshu.album.mapper.AlbumInfoMapper;
import com.atguigu.tingshu.album.mapper.AlbumStatMapper;
import com.atguigu.tingshu.album.mapper.TrackInfoMapper;
import com.atguigu.tingshu.album.service.AlbumAttributeValueService;
import com.atguigu.tingshu.album.service.AlbumInfoService;
import com.atguigu.tingshu.album.service.AuditService;
import com.atguigu.tingshu.common.cache.GuiGuCache;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.rabbit.constant.MqConst;
import com.atguigu.tingshu.common.rabbit.service.RabbitService;
import com.atguigu.tingshu.model.album.AlbumAttributeValue;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.AlbumStat;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.query.album.AlbumInfoQuery;
import com.atguigu.tingshu.vo.album.AlbumAttributeValueVo;
import com.atguigu.tingshu.vo.album.AlbumInfoVo;
import com.atguigu.tingshu.vo.album.AlbumListVo;
import com.atguigu.tingshu.vo.album.AlbumStatVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class AlbumInfoServiceImpl extends ServiceImpl<AlbumInfoMapper, AlbumInfo> implements AlbumInfoService {

    @Autowired
    private AlbumInfoMapper albumInfoMapper;

    //@Autowired
    //private AlbumAttributeValueMapper albumAttributeValueMapper;

    @Autowired
    private AlbumAttributeValueService albumAttributeValueService;

    @Autowired
    private AlbumStatMapper albumStatMapper;

    @Autowired
    private TrackInfoMapper trackInfoMapper;

    @Autowired
    private AuditService auditService;

    @Autowired
    private RabbitService rabbitService;


    /**
     * 新增专辑
     *
     * @param albumInfoVo 专辑VO信息
     * @param userId      用户ID
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveAlbumInfo(AlbumInfoVo albumInfoVo, Long userId) {
        //1.保存专辑信息
        //1.1 将专辑VO（视图对象）对象转为专辑PO（持久化对象）对象
        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);

        //1.2 封装PO对象中用户ID、免费试听集数、专辑状态
        albumInfo.setUserId(userId);
        albumInfo.setTracksForFree(5);
        albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);

        //1.3 保存专辑，得到专辑ID
        albumInfoMapper.insert(albumInfo);
        Long albumId = albumInfo.getId();

        //2.保存专辑标签信息
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (CollUtil.isNotEmpty(albumAttributeValueVoList)) {
            //2.1 将集合泛型从AlbumAttributeValueVo转为AlbumAttributeValue
            List<AlbumAttributeValue> attributeValueList = albumAttributeValueVoList
                    .stream()
                    .map(vo -> {
                        AlbumAttributeValue albumAttributeValue = BeanUtil.copyProperties(vo, AlbumAttributeValue.class);
                        //2.2 为每个专辑标签关系 关联 专辑ID
                        albumAttributeValue.setAlbumId(albumId);
                        return albumAttributeValue;
                    }).collect(Collectors.toList());
            //2.3 批量保存
            albumAttributeValueService.saveBatch(attributeValueList);
        }

        //3.保存专辑统计信息
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_PLAY, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_SUBSCRIBE, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_BUY, 0);
        this.saveAlbumInfoStat(albumId, SystemConstant.ALBUM_STAT_COMMENT, 0);

        //对专辑内容（标题、简介等）进行审核
        String text = albumInfo.getAlbumTitle() + albumInfo.getAlbumIntro();
        String suggestion = auditService.auditText(text);
        if ("pass".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
            //4.采用RabbitMQ可靠性消息将过审专辑存入ES索引库
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, albumId);
        } else if ("block".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);
        } else if ("review".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_ARTIFICIAL);
        }
        albumInfoMapper.updateById(albumInfo);
    }

    /**
     * 保存专辑统计信息
     *
     * @param albumId  专辑ID
     * @param statType 统计类型
     * @param statNum  统计数值 0401-播放量 0402-订阅量 0403-购买量 0403-评论数
     */
    @Override
    public void saveAlbumInfoStat(Long albumId, String statType, int statNum) {
        AlbumStat albumStat = new AlbumStat();
        albumStat.setAlbumId(albumId);
        albumStat.setStatType(statType);
        albumStat.setStatNum(statNum);
        albumStatMapper.insert(albumStat);
    }

    /**
     * 分页查询用户专辑列表包含专辑统计信息
     *
     * @param pageInfo       分页对象
     * @param albumInfoQuery 查询条件
     * @return 分页对象
     */
    @Override
    public IPage<AlbumListVo> findUserAlbumPage(IPage<AlbumListVo> pageInfo, AlbumInfoQuery albumInfoQuery) {
        return albumInfoMapper.findUserAlbumPage(pageInfo, albumInfoQuery);
    }

    /**
     * 删除专辑
     *
     * @param id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeAlbumInfo(Long id) {
        //1.根据专辑ID查询该专辑是否关联声音，如果有则不允许删除专辑
        Long count = trackInfoMapper.selectCount(
                new LambdaQueryWrapper<TrackInfo>()
                        .eq(TrackInfo::getAlbumId, id)
        );
        if (count > 0) {
            throw new GuiguException(500, "该专辑下有声音，请先删除声音再删除专辑");
        }

        //2.删除专辑
        albumInfoMapper.deleteById(id);

        //3.删除专辑统计
        albumStatMapper.delete(
                new LambdaQueryWrapper<AlbumStat>()
                        .eq(AlbumStat::getAlbumId, id)
        );

        //4.删除专辑标签关系
        albumAttributeValueService.remove(
                new LambdaQueryWrapper<AlbumAttributeValue>()
                        .eq(AlbumAttributeValue::getAlbumId, id)
        );

        //5.采用RabbitMQ可靠性消息将从ES索引库删除
        rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_LOWER, id);
    }

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 查询专辑信息
     *
     * @param id
     * @return
     */
    /*@Override
    public AlbumInfo getAlbumInfo(Long id) {
        try {
            //1.优先从分布式缓存Redis中获取业务数据，命中缓存直接返回即可
            //1.1 构建缓存业务数据Key
            String dataKey = RedisConstant.ALBUM_INFO_PREFIX + id;
            //1.2 从Redis获取业务数据
            AlbumInfo albumInfo = (AlbumInfo) redisTemplate.opsForValue().get(dataKey);
            if (albumInfo != null) {
                return albumInfo;
            }
            //2.尝试获取分布式锁
            //2.1 构建锁Key 形式=业务数据Key+锁后缀
            String lockKey = dataKey + RedisConstant.CACHE_LOCK_SUFFIX;
            //2.2 基于RedissonClient对象创建锁对象
            RLock lock = redissonClient.getLock(lockKey);
            //2.3 获取分布式锁
            boolean flag =
                    lock.tryLock(RedisConstant.ALBUM_LOCK_WAIT_PX1, RedisConstant.ALBUM_LOCK_EXPIRE_PX2, TimeUnit.SECONDS);

            //3.获取锁成功，执行查库业务方法，将结果缓存到Redis中，业务执行结束，释放锁
            if (flag) {
                try {
                    //3.1 查询数据库（回源查询）
                    albumInfo = this.getAlbumInfoFromDB(id);
                    //3.2 将查询结果放入Redis中，缓存时间=基础时间+随机时间
                    long ttl = RedisConstant.ALBUM_TIMEOUT + RandomUtil.randomInt(600);
                    redisTemplate.opsForValue().set(dataKey, albumInfo, ttl, TimeUnit.SECONDS);
                    return albumInfo;
                } finally {
                    //3.3 将锁释放
                    lock.unlock();
                }
            } else {
                //4.获取锁失败，自旋
                TimeUnit.MILLISECONDS.sleep(30);
                this.getAlbumInfo(id);
            }
        } catch (Exception e) {
            //5.如果Redis服务可不用，兜底处理：直接查询数据库
            log.error("Redis服务不可用，请检查Redis服务是否正常！");
            return this.getAlbumInfoFromDB(id);
        }
        return null;
    }*/


    /**
     * 查询专辑信息，包含专辑标签列表(直接从数据库中获取)
     *
     * @param id
     * @return
     */
    @Override
    @GuiGuCache(prefix = RedisConstant.ALBUM_INFO_PREFIX)
    public AlbumInfo getAlbumInfoFromDB(Long id) {
        //1.根据专辑ID查询专辑信息
        AlbumInfo albumInfo = albumInfoMapper.selectById(id);

        //2.根据专辑ID查询专辑标签列表
        List<AlbumAttributeValue> albumAttributeValues = albumAttributeValueService.list(
                new LambdaQueryWrapper<AlbumAttributeValue>()
                        .eq(AlbumAttributeValue::getAlbumId, id)
        );
        albumInfo.setAlbumAttributeValueVoList(albumAttributeValues);
        return albumInfo;
    }

    /**
     * 更新专辑信息
     *
     * @param id          专辑ID
     * @param albumInfoVo 专辑VO信息
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateAlbumInfo(Long id, AlbumInfoVo albumInfoVo) {
        //1.更新专辑信息
        AlbumInfo albumInfo = BeanUtil.copyProperties(albumInfoVo, AlbumInfo.class);
        albumInfo.setId(id);
        albumInfoMapper.updateById(albumInfo);

        //2.更新专辑标签关系
        //2.1 根据专辑ID删除原有专辑标签关系
        albumAttributeValueService.remove(
                new LambdaQueryWrapper<AlbumAttributeValue>()
                        .eq(AlbumAttributeValue::getAlbumId, id)
        );
        //2.2 如果有新提交专辑标签关系再次进行新增即可
        List<AlbumAttributeValueVo> albumAttributeValueVoList = albumInfoVo.getAlbumAttributeValueVoList();
        if (CollUtil.isNotEmpty(albumAttributeValueVoList)) {
            //2.1 将集合泛型从AlbumAttributeValueVo转为AlbumAttributeValue
            List<AlbumAttributeValue> attributeValueList = albumAttributeValueVoList
                    .stream()
                    .map(vo -> {
                        AlbumAttributeValue albumAttributeValue = BeanUtil.copyProperties(vo, AlbumAttributeValue.class);
                        //2.2 为每个专辑标签关系 关联 专辑ID
                        albumAttributeValue.setAlbumId(id);
                        return albumAttributeValue;
                    }).collect(Collectors.toList());
            //2.3 批量保存
            albumAttributeValueService.saveBatch(attributeValueList);
        }

        String text = albumInfo.getAlbumTitle() + albumInfo.getAlbumIntro();
        String suggestion = auditService.auditText(text);
        if ("pass".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_PASS);
            //3.采用RabbitMQ可靠性消息将过审专辑存入ES索引库
            rabbitService.sendMessage(MqConst.EXCHANGE_ALBUM, MqConst.ROUTING_ALBUM_UPPER, id);
        } else if ("block".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_NO_PASS);
        } else if ("review".equals(suggestion)) {
            albumInfo.setStatus(SystemConstant.ALBUM_STATUS_ARTIFICIAL);
        }
        albumInfoMapper.updateById(albumInfo);
    }

    /**
     * 查询当前用户专辑列表
     *
     * @return
     */
    @Override
    public List<AlbumInfo> findUserAllAlbumList(Long userId) {
        LambdaQueryWrapper<AlbumInfo> queryWrapper = new LambdaQueryWrapper<>();
        //1.查询当前用户专辑列表
        queryWrapper.eq(AlbumInfo::getUserId, userId);
        //2.专辑状态为审核通过
        queryWrapper.eq(AlbumInfo::getStatus, SystemConstant.ALBUM_STATUS_PASS);
        //3.专辑ID，专辑标题
        queryWrapper.select(AlbumInfo::getId, AlbumInfo::getAlbumTitle);
        //4.限制返回记录数，造成前端卡顿 TODO 后期前端改为带分页下拉框
        queryWrapper.last("limit 200");
        //5.按照专辑ID降序
        queryWrapper.orderByDesc(AlbumInfo::getId);
        return albumInfoMapper.selectList(queryWrapper);
    }

    /**
     * 查询专辑统计信息
     *
     * @param albumId 专辑ID
     * @return
     */
    @Override
    @GuiGuCache(prefix = RedisConstant.ALBUM_INFO_PREFIX + "stat:")
    public AlbumStatVo getAlbumStatVo(Long albumId) {
        return albumInfoMapper.getAlbumStatVo(albumId);
    }

    /**
     * 查询指定状态专辑ID列表
     *
     * @param status
     * @return
     */
    @Override
    public List<Long> findAlbumListByStatus(String status) {
        List<AlbumInfo> albumInfoList = albumInfoMapper.selectList(
                new LambdaQueryWrapper<AlbumInfo>()
                        .eq(AlbumInfo::getStatus, status)
                        .select(AlbumInfo::getId)
        );
        if (CollUtil.isNotEmpty(albumInfoList)) {
            return albumInfoList.stream().map(AlbumInfo::getId).collect(Collectors.toList());
        }
        return null;
    }


}
